// MatchAnalysisServiceImpl.java
package com.mfn.sportjava.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.mfn.sportjava.constants.MessageBuilder;
import com.mfn.sportjava.knowledge.service.KnowledgeBaseService;
import com.mfn.sportjava.model.dto.MatchDTO;
import com.mfn.sportjava.model.enums.AnalysisStyle;
import com.mfn.sportjava.service.MatchAnalysisService;
import com.mfn.sportjava.util.FileUtil;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;

import org.springframework.core.io.InputStreamResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author Anyang
 * @version 1.0.4
 * @date 2025/08/15
 * @description 比赛分析服务实现，支持多种风格，通过并行处理优化性能
 */
@Service
@RequiredArgsConstructor
public class MatchAnalysisServiceImpl implements MatchAnalysisService {
    private static final Logger log = LoggerFactory.getLogger(MatchAnalysisServiceImpl.class);
    private static final String JSON_CONTENT_TYPE = "application/json";
    private static final int MAX_KNOWLEDGE_RESULTS = 15;

    private final ChatClient chatClient;
    private final KnowledgeBaseService knowledgeBaseService;

    @Override
    public InputStreamResource generateAnalysisReport(MultipartFile file, List<String> styleNames) throws IOException {
        validateFile(file);

        List<MatchDTO> matches = FileUtil.parseJsonFile(file.getInputStream());
        if (CollectionUtil.isEmpty(matches)) {
            log.warn("解析JSON文件但未找到比赛数据。");
            throw new IllegalArgumentException("文件内容为空或格式错误");
        }
        log.info("成功从文件 {} 中解析了 {} 场比赛", file.getOriginalFilename(), matches.size());

        List<AnalysisStyle> stylesToAnalyze;
        if (styleNames == null || styleNames.isEmpty()) {
            log.info("未指定分析风格，将使用默认风格: {}", AnalysisStyle.FORMER_PRO.getDisplayName());
            stylesToAnalyze = Collections.singletonList(AnalysisStyle.FORMER_PRO);
        } else {
            stylesToAnalyze = styleNames.stream()
                    .map(AnalysisStyle::fromString)
                    .distinct()
                    .collect(Collectors.toList());
            log.info("请求的分析风格: {}", stylesToAnalyze.stream().map(AnalysisStyle::getDisplayName).collect(Collectors.joining(", ")));
        }

        String reportContent = analysisMatchesWithStyles(matches, stylesToAnalyze);
        return createReportResource(reportContent);
    }

    private void validateFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            log.error("文件上传验证失败：文件为空或不存在。");
            throw new IllegalArgumentException("上传的文件为空");
        }
        String contentType = file.getContentType();
        if (contentType == null || !(contentType.equalsIgnoreCase(JSON_CONTENT_TYPE) || contentType.toLowerCase().startsWith("text/plain"))) {
            log.error("文件上传验证失败：内容类型 '{}' 不正确。期望 '{}' 或 'text/plain'。", contentType, JSON_CONTENT_TYPE);
            throw new IllegalArgumentException("文件类型不正确，仅支持 JSON 格式文件。当前类型: " + contentType);
        }
        log.debug("文件验证成功：{}", file.getOriginalFilename());
    }

    private InputStreamResource createReportResource(String content) {
        return new InputStreamResource(
                new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))
        );
    }

    /**
     * 并行分析比赛数据和所有风格，显著减少总处理时间。
     * @param matches 比赛列表
     * @param stylesToAnalyze 风格列表
     * @return 包含所有分析结果的合并报告字符串
     */
    public String analysisMatchesWithStyles(List<MatchDTO> matches, List<AnalysisStyle> stylesToAnalyze) {
        log.info("开始并行分析 {} 场比赛...", matches.size());

        final List<AnalysisStyle> finalStylesToAnalyze = stylesToAnalyze.isEmpty() ?
                Collections.singletonList(AnalysisStyle.FORMER_PRO) : stylesToAnalyze;

        // 创建一个 CompletableFuture 列表，每个 CompletableFuture 代表一个异步分析任务
        List<CompletableFuture<String>> allAnalysisFutures = matches.stream()
                .flatMap(match -> {
                    String matchIdentifier = match.getMatch();
                    String context = getMatchRelevantKnowledge(match, matchIdentifier);

                    return finalStylesToAnalyze.stream()
                            .map(currentStyle -> {
                                // 为每场比赛和每种风格创建一个异步任务
                                return CompletableFuture.supplyAsync(() -> {
                                    String systemPromptWithStyle = MessageBuilder.getSystemPromptWithStyle(currentStyle);
                                    Message systemMessage = new SystemPromptTemplate(systemPromptWithStyle).createMessage();

                                    String userPromptString = MessageBuilder.buildUserPrompt(match, context);
                                    Message userMessage = new UserMessage(userPromptString);

                                    Prompt prompt = new Prompt(List.of(systemMessage, userMessage));

                                    try {
                                        ChatResponse response = chatClient.call(prompt);
                                        String analysisContent = Optional.ofNullable(response)
                                                .map(ChatResponse::getResult)
                                                .map(Generation::getOutput)
                                                .map(Message::getContent)
                                                .orElse("未能生成分析结果");
                                        log.info("  - 成功生成比赛 {} ({}) 的分析。", matchIdentifier, currentStyle.getDisplayName());
                                        return analysisContent;
                                    } catch (Exception e) {
                                        log.error("  - 调用AI模型时出错，比赛 {} (风格: {}): {}", matchIdentifier, currentStyle.getDisplayName(), e.getMessage());
                                        return String.format("### [%s]\n\n**错误：**\n此比赛在 %s 风格分析下生成失败: %s\n",
                                                matchIdentifier, currentStyle.getDisplayName(), e.getMessage());
                                    }
                                });
                            });
                })
                .toList();

        // 等待所有异步任务完成
        CompletableFuture.allOf(allAnalysisFutures.toArray(new CompletableFuture[0])).join();

        // 收集所有异步任务的结果并合并为单个字符串
        String combinedAnalysis = allAnalysisFutures.stream()
                .map(CompletableFuture::join) // join()会阻塞并返回结果，如果任务失败会抛出异常
                .collect(Collectors.joining("\n\n"));

        log.info("所有分析任务已完成，报告生成成功。");

        return combinedAnalysis;
    }

    /**
     * 获取比赛的特定知识。
     *
     * @param match           比赛信息
     * @param matchIdentifier 比赛标识符
     * @return 特定的知识片段
     */
    private String getMatchRelevantKnowledge(MatchDTO match, String matchIdentifier) {
        List<String> knowledgeSnippets = knowledgeBaseService.searchRelevantKnowledge(match, MAX_KNOWLEDGE_RESULTS);
        String context = knowledgeSnippets.isEmpty()
                ? null
                : String.join("\n---\n", knowledgeSnippets);

        if (context != null) {
            log.info("  - 为比赛 {} 找到 {} 个知识片段。", matchIdentifier, knowledgeSnippets.size());
        } else {
            log.info("  - 未找到比赛 {} 的特定知识。", matchIdentifier);
        }
        return context;
    }
}
